package org.elsfs.cloud.common.mybatis.ext.mybatis.extension;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.commons.compress.utils.Lists;
import org.elsfs.cloud.common.core.entity.BaseEntity;
import org.elsfs.cloud.common.mybatis.ext.sql.AbstractCondition;
import org.elsfs.cloud.common.mybatis.ext.sql.CompositeSqlFragment;
import org.elsfs.cloud.common.mybatis.ext.sql.JoinConditionBuilder;
import org.elsfs.cloud.common.mybatis.ext.sql.JoinType;
import org.elsfs.cloud.common.mybatis.ext.sql.SelectJoinBuilder;
import org.elsfs.cloud.common.mybatis.ext.sql.SqlParameterManager;
import org.elsfs.cloud.common.mybatis.ext.sql.SqlParameterManagerAware;
import org.elsfs.cloud.common.mybatis.ext.sql.TableAliasManager;
import org.elsfs.cloud.common.mybatis.ext.sql.TableAliasManagerAware;
import org.elsfs.cloud.common.mybatis.ext.sql.TokenSqlFragment;
import org.elsfs.cloud.common.mybatis.ext.sql.support.builder.StandardSelectSql;
import org.elsfs.cloud.common.mybatis.ext.sql.support.common.FieldEnumResolverSupport;
import org.elsfs.cloud.common.mybatis.ext.sql.support.common.HierarchyTableAliasManager;
import org.elsfs.cloud.common.mybatis.ext.sql.support.common.SimpleTableAliasManager;
import org.elsfs.cloud.common.mybatis.ext.sql.support.condition.ConditionItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.select.ExpressionSelectItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.select.StandardSelectItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.select.SubQuerySelectItem;
import org.elsfs.cloud.common.util.lang.ArrayUtils;
import org.elsfs.cloud.common.util.lang.CollectionUtils;
import org.elsfs.cloud.common.util.lang.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Join查询包装器
 *
 * @param <E> 实体类型
 */
public class JoinQueryWrapper<E> extends AbstractWrapper<E, String, JoinQueryWrapper<E>>
        implements JoinWrapper<
        JoinQueryWrapper<E>,
        JoinQueryWrapper<E>.WrapperSelectJoinBuilderImpl,
        JoinQueryWrapper<E>.WrapperSelectJoinBuilderImpl.WrapperJoinConditionBuilderImpl>,
        Query<JoinQueryWrapper<E>, E, String>,
        SqlParameterManagerAware,
        TableAliasManagerAware,
        SqlParameterManager {

    /**
     * SQL选择字段
     */
    private final SharedString selectedFields = new SharedString();
    /**
     * 表别名管理器
     */
    private final TableAliasManager tableAliasManager;
    /**
     * Join构建器列表
     */
    private final List<WrapperSelectJoinBuilderImpl> joinBuilders = Lists.newArrayList();
    /**
     * 是否为自定义SQL选择字段
     */
    private boolean defaultSelectedFieldsCleared;

    public JoinQueryWrapper(E entity) {
        super.setEntity(entity);
        super.initNeed();
        this.tableAliasManager = new SimpleTableAliasManager();
        this.tableAliasManager.registerAlias(super.getEntityClass(), JoinWrapper.TABLE_ALIAS);
    }
    public JoinQueryWrapper(Class<E> entityClass) {
        super.setEntityClass(entityClass);
        super.initNeed();

        this.tableAliasManager = new SimpleTableAliasManager();
        this.tableAliasManager.registerAlias(entityClass, JoinWrapper.TABLE_ALIAS);
    }

    public JoinQueryWrapper(Class<E> entityClass, TableAliasManager tableAliasManager) {
        super.setEntityClass(entityClass);
        super.initNeed();

        this.tableAliasManager = tableAliasManager;
        this.tableAliasManager.registerAlias(entityClass, JoinWrapper.TABLE_ALIAS);
    }

    /**
     * 非对外公开的构造方法,只用于生产嵌套 sql
     *
     * @param entityClass 本不应该需要的
     */
    private JoinQueryWrapper(E entity, Class<E> entityClass, AtomicInteger paramNameSeq,
                             Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments,
                             SharedString lastSql, SharedString sqlComment, SharedString sqlFirst, TableAliasManager tableAliasManager) {
        super.setEntity(entity);
        super.setEntityClass(entityClass);
        this.paramNameSeq = paramNameSeq;
        this.paramNameValuePairs = paramNameValuePairs;
        this.expression = mergeSegments;
        this.lastSql = lastSql;
        this.sqlComment = sqlComment;
        this.sqlFirst = sqlFirst;
        this.tableAliasManager = tableAliasManager;

        this.tableAliasManager.registerAlias(entityClass, JoinWrapper.TABLE_ALIAS);
    }

    /**
     * 子类返回一个自己的新对象
     */
    @Override
    protected JoinQueryWrapper<E> instance() {
        return new JoinQueryWrapper<>(
                this.getEntity(),
                this.getEntityClass(),
                this.paramNameSeq,
                this.paramNameValuePairs,
                new MergeSegments(),
                SharedString.emptyString(),
                SharedString.emptyString(),
                SharedString.emptyString(),
                this.tableAliasManager
        );
    }

    /**
     * 内连接一张表
     *
     * @param entityClass 实体类
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(Class<? extends BaseEntity> entityClass) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.INNER_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName());
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 左连接一张表
     *
     * @param entityClass 实体类
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(Class<? extends BaseEntity> entityClass) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.LEFT_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName());
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 右连接一张表
     *
     * @param entityClass 实体类
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(Class<? extends BaseEntity> entityClass) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.RIGHT_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName());
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 内连接一张表
     *
     * @param entityClass 实体类
     * @param tableAlias  表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(Class<? extends BaseEntity> entityClass, String tableAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.INNER_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 左连接一张表
     *
     * @param entityClass 实体类
     * @param tableAlias  表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(Class<? extends BaseEntity> entityClass, String tableAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.LEFT_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 右连接一张表
     *
     * @param entityClass 实体类
     * @param tableAlias  表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(Class<? extends BaseEntity> entityClass, String tableAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.RIGHT_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 内连接一张表
     *
     * @param entityClass   实体类
     * @param tableAlias    表别名
     * @param registerAlias 是否注册别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(Class<? extends BaseEntity> entityClass, String tableAlias, boolean registerAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.INNER_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias, registerAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 左连接一张表
     *
     * @param entityClass   实体类
     * @param tableAlias    表别名
     * @param registerAlias 是否注册别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(Class<? extends BaseEntity> entityClass, String tableAlias, boolean registerAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.LEFT_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias, registerAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 右连接一张表
     *
     * @param entityClass   实体类
     * @param tableAlias    表别名
     * @param registerAlias 是否注册别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(Class<? extends BaseEntity> entityClass, String tableAlias, boolean registerAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.RIGHT_JOIN, TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias, registerAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 内连接一张表
     *
     * @param table 数据库表名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(String table) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.INNER_JOIN, table);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 左连接一张表
     *
     * @param table 数据库表名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(String table) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.LEFT_JOIN, table);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 右连接一张表
     *
     * @param table 数据库表名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(String table) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.RIGHT_JOIN, table);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 内连接一张表
     *
     * @param table      数据库表名
     * @param tableAlias 表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(String table, String tableAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.INNER_JOIN, table, tableAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 左连接一张表
     *
     * @param table      数据库表名
     * @param tableAlias 表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(String table, String tableAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.LEFT_JOIN, table, tableAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 右连接一张表
     *
     * @param table      数据库表名
     * @param tableAlias 表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(String table, String tableAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.RIGHT_JOIN, table, tableAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 内连接一张表
     *
     * @param table         数据库表名
     * @param tableAlias    表别名
     * @param registerAlias 是否注册别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(String table, String tableAlias, boolean registerAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.INNER_JOIN, table, tableAlias, registerAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 左连接一张表
     *
     * @param table         数据库表名
     * @param tableAlias    表别名
     * @param registerAlias 是否注册别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(String table, String tableAlias, boolean registerAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.LEFT_JOIN, table, tableAlias, registerAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 右连接一张表
     *
     * @param table         数据库表名
     * @param tableAlias    表别名
     * @param registerAlias 是否注册别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(String table, String tableAlias, boolean registerAlias) {
        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(JoinType.RIGHT_JOIN, table, tableAlias, registerAlias);
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 子查询JOIN
     *
     * @param sqlBuilderConsumer 子查询SQL构建器
     * @param tableAlias         临时表别名
     * @param joinType           连接类型
     * @return 连接配置对象
     */
    private WrapperSelectJoinBuilderImpl doSubQueryJoin(Consumer<StandardSelectSql> sqlBuilderConsumer, String tableAlias, JoinType joinType) {
        if (StringUtils.isBlank(tableAlias)) {
            throw new MybatisPlusException("JOIN子查询的表别名不能为空");
        }

        StandardSelectSql standardSelectSql = new StandardSelectSql(
                this.getSqlParameterManager(),
                new HierarchyTableAliasManager(
                        new SimpleTableAliasManager(),
                        this.getTableAliasManager()
                )
        );
        sqlBuilderConsumer.accept(standardSelectSql);

        WrapperSelectJoinBuilderImpl joinBuilder = new WrapperSelectJoinBuilderImpl(
                joinType,
                "(" + standardSelectSql.buildSqlFragment() + ")",
                tableAlias
        );
        this.joinBuilders.add(joinBuilder);
        return joinBuilder;
    }

    /**
     * 内连接一个子查询
     *
     * @param sqlBuilderConsumer 子查询构建器
     * @param tableAlias         表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl join(Consumer<StandardSelectSql> sqlBuilderConsumer, String tableAlias) {
        return this.doSubQueryJoin(sqlBuilderConsumer, tableAlias, JoinType.INNER_JOIN);
    }

    /**
     * 左连接一个子查询
     *
     * @param sqlBuilderConsumer 子查询构建器
     * @param tableAlias         表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl leftJoin(Consumer<StandardSelectSql> sqlBuilderConsumer, String tableAlias) {
        return this.doSubQueryJoin(sqlBuilderConsumer, tableAlias, JoinType.LEFT_JOIN);
    }

    /**
     * 右连接一个子查询
     *
     * @param sqlBuilderConsumer 子查询构建器
     * @param tableAlias         表别名
     * @return 连接配置对象
     */
    @Override
    public WrapperSelectJoinBuilderImpl rightJoin(Consumer<StandardSelectSql> sqlBuilderConsumer, String tableAlias) {
        return this.doSubQueryJoin(sqlBuilderConsumer, tableAlias, JoinType.RIGHT_JOIN);
    }

    /**
     * 获取JOIN的SQL片段
     *
     * @return SQL片段
     */
    @Override
    public String getJoinSqlSegment() {
        return this.buildSqlFragment();
    }

    /**
     * 是否自定义选择字段
     *
     * @return bool
     */
    @Override
    public boolean isClearedDefaultSelectedFields() {
        return this.defaultSelectedFieldsCleared;
    }

    /**
     * 自定义SQL选择字段
     *
     * @return this
     */
    @Override
    public JoinQueryWrapper<E> clearDefaultSelectedFields() {
        this.defaultSelectedFieldsCleared = true;
        return this;
    }

    /**
     * 自定义选择字段
     *
     * @param fields 字段列表
     * @return this
     */
    @Override
    public JoinQueryWrapper<E> select(String... fields) {
        if (ArrayUtils.isNotEmpty(fields)) {
            this.selectedFields.setStringValue(
                    JoinWrapper.mergeSelectedFields(this.selectedFields.getStringValue(), fields)
            );
        }

        return this;
    }

    /**
     * 指定查询字段
     *
     * @param condition 执行条件
     * @param columns   字段列表
     * @return children
     */
    @Override
    public JoinQueryWrapper<E> select(boolean condition, List<String> columns) {
        return null;
    }


    /**
     * 自定义选择字段
     *
     * @param fields 字段集合
     * @return this
     */
    public JoinQueryWrapper<E> select(Collection<String> fields) {
        if (CollectionUtils.isNotEmpty(fields)) {
            this.selectedFields.setStringValue(
                    JoinWrapper.mergeSelectedFields(this.selectedFields.getStringValue(), fields)
            );
        }

        return this;
    }

    /**
     * 过滤查询的字段信息(主键除外!)
     * <p>例1: 只要 java 字段名以 "test" 开头的             -> select(i -> i.getProperty().startsWith("test"))</p>
     * <p>例2: 只要 java 字段属性是 CharSequence 类型的     -> select(TableFieldInfo::isCharSequence)</p>
     * <p>例3: 只要 java 字段没有填充策略的                 -> select(i -> i.getFieldFill() == FieldFill.DEFAULT)</p>
     * <p>例4: 要全部字段                                   -> select(i -> true)</p>
     * <p>例5: 只要主键字段                                 -> select(i -> false)</p>
     *
     * @param entityClass 实体类
     * @param predicate   过滤方式
     * @return children
     */
    @Override
    public JoinQueryWrapper<E> select(Class<E> entityClass, Predicate<TableFieldInfo> predicate) {
        super.setEntityClass(entityClass);
        this.selectedFields.setStringValue(TableInfoHelper.getTableInfo(getEntityClass()).chooseSelect(predicate));
        return this;
    }

    /**
     * 查询字段 SQL 片段
     *
     * @return SQL片段
     */
    @Override
    public String getSqlSelect() {
        return this.selectedFields.getStringValue();
    }

    /**
     * 构建SQL片段
     *
     * @return SQL片段
     */
    @Override
    public String buildSqlFragment() {
        if (this.joinBuilders.isEmpty()) {
            return "";
        }

        return this.joinBuilders.stream()
                .map(CompositeSqlFragment::buildSqlFragment)
                .collect(Collectors.joining(" "));
    }

    /**
     * 注册SQL参数
     *
     * @param value 参数值
     * @return 参数名称
     */
    @Override
    public String registerParameter(Object value) {
        final String genParamName = Constants.WRAPPER_PARAM + paramNameSeq.incrementAndGet();
        final String paramStr = getParamAlias() + Constants.WRAPPER_PARAM_MIDDLE + genParamName;
        paramNameValuePairs.put(genParamName, value);
        return paramStr;
    }

    /**
     * 获取SQL参数
     *
     * @return SQL参数
     */
    @Override
    public Map<String, Object> getSqlParameters() {
        return this.paramNameValuePairs;
    }

    /**
     * 获取SQL参数管理器
     *
     * @return SQL参数管理器
     */
    @Override
    public SqlParameterManager getSqlParameterManager() {
        return this;
    }

    /**
     * 获取表别名管理器
     *
     * @return 表名别管理器
     */
    @Override
    public TableAliasManager getTableAliasManager() {
        return this.tableAliasManager;
    }

    /**
     * 查询Join构建器实现
     */
   public class WrapperSelectJoinBuilderImpl extends CompositeSqlFragment implements SelectJoinBuilder<WrapperSelectJoinBuilderImpl, WrapperSelectJoinBuilderImpl.WrapperJoinConditionBuilderImpl, JoinQueryWrapper<E>>, SqlParameterManagerAware, TableAliasManagerAware {

        /**
         * 连接类型
         */
        private final JoinType joinType;
        /**
         * 连接表名称
         */
        private final String table;
        /**
         * 连接表别名
         */
        private final String tableAlias;
        /**
         * Join条件构建器
         */
        private WrapperJoinConditionBuilderImpl joinConditionBuilder;

        protected WrapperSelectJoinBuilderImpl(JoinType joinType, String table, String tableAlias, boolean registerAlias) {
            this.joinType = joinType;
            this.table = table;

            this.tableAlias = tableAlias;
            if (registerAlias) {
                JoinQueryWrapper.this.tableAliasManager.registerAlias(table, this.tableAlias);
            }
        }

        protected WrapperSelectJoinBuilderImpl(JoinType joinType, String table, String tableAlias) {
            this(
                    joinType,
                    table,
                    tableAlias,
                    true
            );
        }

        protected WrapperSelectJoinBuilderImpl(JoinType joinType, String table) {
            this(
                    joinType,
                    table,
                    JoinQueryWrapper.this.tableAliasManager.generateAlias(table),
                    true
            );
        }

        /**
         * 解析字段枚举名称
         *
         * @param field 字段枚举
         * @return 字段名称
         */
        protected String resolveFieldName(Enum<?> field) {
            return FieldEnumResolverSupport.resolveFieldName(
                    this.getTableAliasManager(),
                    field
            );
        }

        /**
         * 返回上一级对象
         *
         * @return 上级对象
         */
        @Override
        public JoinQueryWrapper<E> end() {
            return JoinQueryWrapper.this;
        }

        /**
         * 连接条件设置
         *
         * @return 连接条件构建器
         */
        @Override
        public WrapperJoinConditionBuilderImpl on() {
            this.joinConditionBuilder = new WrapperJoinConditionBuilderImpl();
            return this.joinConditionBuilder;
        }

        /**
         * 构建SQL之前处理
         */
        @Override
        protected void beforeBuild() {
            this.addSqlFragment(
                    new TokenSqlFragment(this.joinType.getJoinKeyword())
            );
            this.addSqlFragment(
                    new TokenSqlFragment(
                            this.table + " AS " + this.tableAlias
                    )
            );
            this.addSqlFragment(this.joinConditionBuilder);
        }

        /**
         * 获取SQL参数管理器
         *
         * @return SQL参数管理器
         */
        @Override
        public SqlParameterManager getSqlParameterManager() {
            return JoinQueryWrapper.this.getSqlParameterManager();
        }

        /**
         * 选择关联SQL字段
         *
         * @param fields SQL字段
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl select(String... fields) {
            if (ArrayUtils.isEmpty(fields)) {
                return this;
            }

            List<String> portionSelectedFields = new ArrayList<>(fields.length);
            for (String field : fields) {
                portionSelectedFields.add(
                        this.buildSelectField(field)
                );
            }

            JoinQueryWrapper.this.select(portionSelectedFields);
            return this;
        }

        /**
         * 选择关联SQL字段表达式
         *
         * @param expressions SQL字段表达式
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectExpression(String... expressions) {
            if (ArrayUtils.isEmpty(expressions)) {
                return this;
            }

            List<String> portionSelectedExpressions = new ArrayList<>(expressions.length);
            for (String expression : expressions) {
                portionSelectedExpressions.add(
                        this.buildSelectExpression(expression)
                );
            }

            JoinQueryWrapper.this.select(portionSelectedExpressions);
            return this;
        }

        /**
         * 选择关联SQL字段
         *
         * @param fields SQL字段枚举
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl select(Enum<?>... fields) {
            if (ArrayUtils.isEmpty(fields)) {
                return this;
            }

            List<String> portionSelectedFields = new ArrayList<>(fields.length);
            for (Enum<?> field : fields) {
                portionSelectedFields.add(
                        this.buildSelectField(
                                this.resolveFieldName(field)
                        )
                );
            }

            JoinQueryWrapper.this.select(portionSelectedFields);
            return this;
        }

        /**
         * 选择SQL字段
         *
         * @param field      SQL字段
         * @param fieldAlias 字段别名
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectAs(String field, String fieldAlias) {
            if (StringUtils.isBlank(fieldAlias)) {
                throw new MybatisPlusException("选择字段[" + field + "]的别名不能为空");
            }

            return this.select(
                    field + " AS " + fieldAlias
            );
        }

        /**
         * 选择SQL字段
         *
         * @param field      SQL字段枚举
         * @param fieldAlias 字段别名
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectAs(Enum<?> field, String fieldAlias) {
            return this.selectAs(
                    this.resolveFieldName(field),
                    fieldAlias
            );
        }

        /**
         * 选择SQL字段
         *
         * @param field      SQL字段枚举
         * @param fieldAlias 字段别名枚举
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectAs(Enum<?> field, Enum<?> fieldAlias) {
            return this.selectAs(field, fieldAlias.name());
        }

        /**
         * 选择子查询结果
         *
         * @param sqlBuilderConsumer SQL构建器消费器
         * @param fieldAlias         字段别名
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectAs(Consumer<StandardSelectSql> sqlBuilderConsumer, String fieldAlias) {
            if (StringUtils.isBlank(fieldAlias)) {
                throw new MybatisPlusException("选择子查询的字段别名不能为空");
            }

            StandardSelectSql standardSelectSql = new StandardSelectSql(
                    this.getSqlParameterManager(),
                    new HierarchyTableAliasManager(
                            new SimpleTableAliasManager(),
                            this.getTableAliasManager()
                    )
            );
            sqlBuilderConsumer.accept(standardSelectSql);

            return this.select(
                    new SubQuerySelectItem(
                            standardSelectSql.buildSqlFragment(),
                            fieldAlias
                    ).buildSqlFragment()
            );
        }

        /**
         * 选择子查询结果
         *
         * @param sqlBuilderConsumer SQL构建器消费器
         * @param fieldAlias         字段别名枚举
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectAs(Consumer<StandardSelectSql> sqlBuilderConsumer, Enum<?> fieldAlias) {
            return this.selectAs(sqlBuilderConsumer, fieldAlias.name());
        }

        /**
         * 选择关联SQL字段
         *
         * @param fields SQL字段
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl select(Collection<String> fields) {
            List<String> portionSelectedFields = new ArrayList<>(fields.size());
            for (String field : fields) {
                portionSelectedFields.add(
                        this.buildSelectField(field)
                );
            }

            JoinQueryWrapper.this.select(portionSelectedFields);
            return this;
        }

        /**
         * 构建选择SQL字段
         *
         * @param field SQL字段
         * @return 选择SQL字段
         */
        private String buildSelectField(String field) {
            StandardSelectItem selectItem = new StandardSelectItem(field);
            if (StringUtils.isBlank(selectItem.getTableAlias())) {
                selectItem = new StandardSelectItem(this.tableAlias, selectItem.getField(), selectItem.getFieldAlias());
            }

            return selectItem.buildSqlFragment();
        }

        /**
         * 构建选择SQL字段表达式
         *
         * @param expression SQL字段表达式
         * @return 选择SQL字段表达式
         */
        private String buildSelectExpression(String expression) {
            return new ExpressionSelectItem(expression)
                    .buildSqlFragment();
        }

        /**
         * 选择关联SQL字段表达式
         *
         * @param expressions SQL字段表达式
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectExpression(Collection<String> expressions) {
            if (CollectionUtils.isEmpty(expressions)) {
                return this;
            }

            List<String> portionSelectedExpressions = new ArrayList<>(expressions.size());
            for (String expression : expressions) {
                portionSelectedExpressions.add(
                        this.buildSelectExpression(expression)
                );
            }

            JoinQueryWrapper.this.select(portionSelectedExpressions);
            return this;
        }

        /**
         * 选择关联SQL字段
         *
         * @param fields SQL字段枚举
         * @return 具体实现
         */
        @Override
        public WrapperSelectJoinBuilderImpl selectEnum(Collection<Enum<?>> fields) {
            if (CollectionUtils.isEmpty(fields)) {
                return this;
            }

            List<String> portionSelectedFields = new ArrayList<>(fields.size());
            for (Enum<?> field : fields) {
                portionSelectedFields.add(
                        this.buildSelectField(
                                this.resolveFieldName(field)
                        )
                );
            }

            JoinQueryWrapper.this.select(portionSelectedFields);
            return this;
        }

        /**
         * 获取表别名管理器
         *
         * @return 表名别管理器
         */
        @Override
        public TableAliasManager getTableAliasManager() {
            return JoinQueryWrapper.this.tableAliasManager;
        }

        /**
         * Join条件构建器实现
         */
        public class WrapperJoinConditionBuilderImpl extends AbstractCondition<WrapperJoinConditionBuilderImpl> implements JoinConditionBuilder<WrapperJoinConditionBuilderImpl, WrapperSelectJoinBuilderImpl, JoinQueryWrapper<E>> {

            /**
             * Join条件列表
             */
            private final List<ConditionItem> conditionItems = Lists.newArrayList();

            /**
             * 获取SQL参数管理器
             *
             * @return SQL参数管理器
             */
            @Override
            public SqlParameterManager getSqlParameterManager() {
                return WrapperSelectJoinBuilderImpl.this.getSqlParameterManager();
            }

            /**
             * 添加一个条件
             *
             * @param conditionItem 条件
             */
            @Override
            public void addConditionItem(ConditionItem conditionItem) {
                this.conditionItems.add(conditionItem);
            }

            /**
             * 返回上一级对象
             *
             * @return 上级对象
             */
            @Override
            public JoinQueryWrapper<E> end() {
                return WrapperSelectJoinBuilderImpl.this.end();
            }

            /**
             * 构建SQL片段
             *
             * @return SQL片段
             */
            @Override
            public String buildSqlFragment() {
                if (this.conditionItems.isEmpty()) {
                    return " ";
                }

                return String.format(
                        "ON %s",
                        ConditionItem.stripHeaderKeyword(
                                this.conditionItems.stream()
                                        .map(ConditionItem::buildSqlFragment)
                                        .collect(Collectors.joining(" "))
                        )
                );
            }

            /**
             * 获取表别名管理器
             *
             * @return 表名别管理器
             */
            @Override
            public TableAliasManager getTableAliasManager() {
                return WrapperSelectJoinBuilderImpl.this.getTableAliasManager();
            }
        }
    }
}
